/*
-----------------------------------------------------------------------------
This source file is part of command_agent.
The project of Engineering Lab, dept. of CSIE, NTNU.

Copyright (c) 2000-2006 The Engineering Lab, dept. of CSIE, NTNU.
-----------------------------------------------------------------------------
Filename:    command_agent.cpp
Description: This is a cpp source file to implement the method in the header file.
Written by:  Ming Jie Chiou. 
Update note: 12/27
             12/28 - A. 將method visualize()中的送出show p的部分，改成以下的流程
			           1.送出ask p以取得type
					   2.呼叫wopm.createEntry(name,type)
					   3.由wopm以getValue來取得所要的資料
				     B.將parseHashCode改為parseValue
					 C.修改method parseType
			 12/30 - A.完成undold的功能，但在get the class name 之前，應要作type check
			           以免不是ref type的entry作了unfold的動作。但目前尚未加入此判斷條件。
		     01/10 - 跟JDB server thread 整合成功，完成unfold 的功能
			 01/24 - 完成string split的功能
			 01/29 - 1、unfold 第二層時，目前必須先visualize test.a，再unfold test.a。因為存在wopm中的entry是以"a"
			            而不是以"test.a"的名字存於wopm中。 (覺得直接改成unfold test.a可直接執行較直覺)
					 2、unfold array，目前只是印出array內所有的entry的值，但未來若是有不是primitive的entry，
					    則在再次的unfold時，在wopm中會找不到這個entry。故需配合第一項一起進行考慮，是否讓ca替user
						new出第二層以後的entry，抑或是讓使用者先"visualize"後，再unfold。
						個人觀點：以user-friendly的角度來說，應該要替使用者new出來才是。但若是在array的維度很大時候
						          似乎又不是很好的方法。
		     02/09 - 1、unfold ref的類別分兩種，一種是unfold最上層，一種是unfold 內層。
			            unfold最上層的話，其entry已在wopm中，則create
						unfold內層的話，必須找到其上一層，再create該層的obj entry
						<以上都是指ref而言，unfold array的話，另外有處理的方式>
					 2、unfold的對象分四種：
					    A.unfold ref
						B.unfold array
						C.unfold array of array
						D.unfold array of ref
			 02/13 - 在unfold test.a時，本以為a的parent為test，但實際上其parent為test的object entry
			 02/17 - 1、在unfold array時，要新增的array會有目前是null的值的可能，如此則尚需考慮作法…
			         2、另外，unfold array of ref時，會新增很多的object的entry(一個entry就會新增其下所有的member)
					 3、ask test.list3時，因為list3為poly照type，所以會出現<VARNAME>  test.list3 <UNKNOWN> NULL <ID> 0
					    其list3會出現unknown。故應該要再作修正，修正成<VARNAME>  test.list3 <REFTYPE> demo.Poly <ID> xxx。
						但是有一項難處，就是因為其未分配記憶體，故為null pointer，修正的方法：判斷是否為null pointer
						若為null，則不予以unfold的權力，即不允許其unfold。
			 02/24 - 1、完成unfold1D的primitive type的功能，在unfold 時，為了其 "Actual Path"的問題卡了一點時間，
			            但還是順利完成。接下來要測試unfold2D的功能。測完後要再測試複雜的資料結構，如array of ref…等。
			 02/25 - 測試了array of reference以及reference of array，例如：unfold test.a.list1；unfold test.a.termArr[0]
			         目前是在array of ref有字串剖析上的問題，待解之
			 02/26 - 解決2/25日所發生的問題，因為改寫了本身的search 與wopm中的method - search，其改寫wopm的search的原因
			         寫在wopm的search method中；而command agent中的search就直接拿掉了
			 02/27 -
			 02/28 - 加入method get array length，用以取得2維、3維陣列的長度。
			 03/01 - 測試unfold2D時發生問題，懷疑是ca跟jdb溝通時的延遲問題，但是在ca中是用無窮迴圈去接，不知道為何會讓jdb來不及反應
			         ，而用step作trace時，就沒有問題，de了很久de不出來@@。
					 但是3/2換到學校的電腦測試，就ok了。看到ghost.....還我3/1的春青來…
			 03/02 - unfold3D的array OK，但尚未測試複雜的資料結構如：array of ref or ref of array
			         因為unfold1D unfold2D unfold3D其重複的部分太多，故將其重複的部分寫成一個method，分離其不同的部分。
			 03/04 - 合併了unfold1D 2D 3D的重複部份至unfoldArray，並把所有送出字串的部分改成CMD_ 或TYPE_ 的型式。
			*03/05 - *合併了unfold1D 2D 3D，讓unfold3D可以call unfold 2D, unfold2D 可以call unfold1D，達到程式重複利用的目的。
			         *初步可以測試unfold, visualize的指令，但尚未完成warning的去除以及update的測試。
			*03/06 - *完成vector的轉移，將原本使用smith所寫的Vector，改成c++ STL中的vectors
			 03/07 - 在解決與yajdb溝通的問題，尤其是在當yajdb送出continue後，會與jdb 執行command時的thread輸出到同一個螢幕上，此會導至
			         將不是ca所要的資訊送至ca。原本覺得是thread之間的協調出了問題，後來發現應該是jdb server thread與user interface的
					 判斷cmd是作在同一段程式裡面，實際上應該要分離出來。所以…應該要把jdb server thread分離出來。
			 03/13 - 發現有一個問題，原本的_parent是指到自己，但由於認知的問題，後來改成_parent即為指到自己的parent，
			*03/14 - 3/13所發現的問題，其實並非問題，真正的問題在於wopm中的search()。
			         對於一個entry來說，actual path 為unique。但是對ref的entry來說，其obj entry的actual path與之相同。
					 故不能光以actual path來作key的判斷，而要以parent以及name作為一組key。
		   **03/17 - 經過昨天一天的努力，終於把wopm中的search() method改完。
			         因為輸入的訊息的format可能有：(1)、name
					                               (2)、name[]
												   (3)、name1.name2
												   (4)、name1[].name2
												   (5)、name1.namr2[]
												   (6)、name1[].name2[]
												   (7)、name1.name2@location
												   (8)、istance of type ~
					 所以把其中把 (1)、(7)、(8)歸為一類，剩餘的歸為一類。
					 符合()、()、()格式的會直接作search，而其他的則是會先在[]之前加上DOT，讓接下來的split能順利進行
					 (因為在wopm中沒有name[]這樣的entry，只有[]這樣的entry，故先在"["之前加上DOT，讓接下來能順利進行切割)。
			 03/18 - 想到幾個問題：
			         (1)當unfold完，再fold後，wopm中的entry是否應該刪除?
					    目前決定不刪除，待run到下一個中斷點後，再刪除讓使用者重新unfold。
					 (2)但上述會有一個問題，當有兩個指標指到同一個物件時，若是pointer1 unfold過，
					    那麼pointer2是否允許unfold?
						目前程式的寫法是不允許，因為object entry已存在，故不允許。
						我亦覺得這樣比較直觀。
					 (3)update的時候，應該把所有object entry delete，然後更改object的vm，讓使用者再次展開
			 03/19 - debug de一整天 -- 我們在create object entry 時，由於我們會先create entry出來，
			         但是若是發現在wopm中已有object entry，則不會新增，但是，原本回傳的時候卻不會回傳已存在的entry，
					 所以在getActualPath時，parent是null。
			 03/20 - 修正3/19的錯誤，在wopm::getInstance()->addEntry之前，先行判斷是否有此entry的存在，若有，則回傳之，
			         若無，才回傳新增的object entry。
			 03/21 - 加入新的測資 testcaseE，主要測試指回自己的指標的問題。 
			 03/21 - 
	  2008   05/05 - ypc. This command_agent has been totally rewritten to add a new field called "ADDR"
	  2009   10/05 - hyt. retrieveWOP 新增行號

-----------------------------------------------------------------------------
*/
#include "Command_Agent.h"
#include "MappingEngine.h"
//#include "MappingTree.h"
#include <sstream>
#include "dummyVM.h"
#include "Layout_Assistant.h"
#include "ExplorBotLibrary.h"
#include "LayoutLibrary.h"

#include "xNodeType.h"
#include "xNodeType_VM.h"
#include "xNodeType_vmcollector.h"
#include "xNodeType_WOP.h"
#include "xNodeType_Math.h"
#include "xNodeType_StringComposer.h"
#include "Factory_xNodeType.h"
#include "xMappingNodeTypeLibrary.h"
#include "InterpolationCenter.h"

#include "DIVA_Application.h"	// 使用log
#include "MessageBoxProxy.h"
#include "MDSParser.h"
#include "WOP_Entry.h"
#include "WOP_Obj_Entry.h"
#include "WOPM.h"
//////////////////////////////////////////////////////////////////////////
// xTitan test automation
#include <xTitanClient/xTitan.hpp>
#include "xSocketClient.h"
//////////////////////////////////////////////////////////////////////////
#include "CommandServer.h"
//20121230 加入動畫 
#include "LayoutInterpolation.h"



extern HWND _hWnd ; // the global variable to be used by mapping engine GUI

vector<std::string> TestingRobot(vector<std::string> s);
vector<string> pri_types ;

bool isPriType(string type) ;
std::string combine_tokens(vector<string> tokens);
bool isNumber(string str);

Command_Agent* Command_Agent::ca=NULL;
/// constructor
Command_Agent::Command_Agent( const std::string & clientIP ){

	//連到jdb server thread 的socket
	/*
	connectIP = clientIP;
	port = CONNECT_PORT;

	if ( xIsTesting() ){
		socket_s = new xSocketClient(connectIP, port);
	} else{
		socket_s = new SocketClient(connectIP,port);
	}
	*/
	this->connect( &CommandServer::instance(), SIGNAL( visualize( const QString & ) ), SLOT( onVisualize( const QString & ) ) );
	this->connect( &CommandServer::instance(), SIGNAL( update() ), SLOT( onUpdate() ) );
	this->connect( &CommandServer::instance(), SIGNAL( anime(const QString & ) ), SLOT( onAnime( const QString &) ) );
	
	scriptmode = false;
//	MappingDialogProxy::getInstance();
}

/// destructor
Command_Agent::~Command_Agent(void){
	//delete socket_s;
	delete ca;
}

void Command_Agent::initialize( const std::string & clientIP ) {
	if( ca != NULL ) {
		return;
	}
	ca = new Command_Agent( clientIP );
	pri_types.push_back("int");
	pri_types.push_back("long");
	pri_types.push_back("char");
	pri_types.push_back("float");
	pri_types.push_back("double");
	pri_types.push_back("String");
	pri_types.push_back("bool");
}

/// get Instance()
Command_Agent* Command_Agent::getInstance(){
	assert( ca != NULL || !"Command_Agent not initialized" );
	return ca;
}
// en is the wop entry that is found to have the same address
// parent is the new wop entry's parent
bool isSameFamily(WOP_Entry *en, WOP_Entry *parent) {
	// there is a case where cool2d[2][2]
	// where cool2d, cool2d[0][0] and cool2d[0][0].x have the same address
	// so we need to check if en is in anyone of them 

	WOP_Entry *p ;
	p = parent ;
	while (p != NULL) { 
		if (en == p) 
			return true ;
		p = p->getParent();
	}
	return false ;
}
/// visualize
//  this method is called when in debugger a "visualize p" command is invoked.
WOP_Entry* Command_Agent::retrieveWOP(std::string _visualItem, WOP_Entry *parent, WOP_Entry* from, bool top,  std::string known_vartype="") {	
	string vartype, addr, woptype ;

	/// 取得type of the variable so that we can determine what kind of WOP_entry should
	// be initialized.
	
	auto askdata = CommandServer::instance().ask( _visualItem.c_str() ).toMap();

	vartype = askdata["<VARTYPE>"].toString().toStdString() ;
	addr = askdata["<ADDR>"].toString().toStdString() ;
	
	WOP_Entry * en = WOPM::getInstance()->check_existing_objects(addr);
	if (en != NULL) 
		if (! isSameFamily(en,parent)) return en  ;	  // the address exists in the WOPM already.
	                                               // in the case class cool { int x, int y }
	                                               // cool.x and cool have the same address
	                                               // so, when we expand cool.x, we want to 
	                                               // make sure that cool.x's parent is not cool

	if (known_vartype != "" && vartype == "!bad!") {
		vartype = known_vartype ;  // this is the case in the bt.java where _visualItem = root.left.right.left
		                           // Its value is "null", so Minerva can not get the type and it returns null 
								   // known_type is passed by the callers (unfoldObject and unfoldArray)
		                           // Known_type is set in the STRUCT command.
	}
	//if (known_vartype != "") 
	//	assert(vartype == known_vartype);
	woptype = determine_wop_type(vartype);
	
	if (isPriType(woptype)) {
		en = WOPM::getInstance()->createEntry(_visualItem,woptype,parent, from, top, vartype, addr);
		WOPM::getInstance()->addEntry(en);
	} else if (woptype == "ref") {
		en = WOPM::getInstance()->createEntry(_visualItem,woptype,parent, from, top , vartype, addr);
		WOPM::getInstance()->addEntry(en);
	} else if (woptype == "array") { 
		en = newArrayEntry(_visualItem, parent, from, top, vartype, addr);
		WOPM::getInstance()->addEntry(en);
		unfoldArray(dynamic_cast<WOP_Array_Entry*>(en), top);
	} else if (woptype == "object") {
	   en = newObjEntry(_visualItem, parent, from, top, vartype, addr);
	   if( !en ) {
		   // address is invalid
		   return nullptr;
	   }
	   WOPM::getInstance()->addEntry(en);
	   unfoldObject(dynamic_cast<WOP_Obj_Entry*>(en),top);
	}
	assert(en != NULL);
	/// 加到wopm中	
	
	/// show 出所有的wopm entry info.
	//WOPM::getInstance()->showAll("The end of retrieve WOP");
	return en ;
}

void Command_Agent::onVisualize( const QString & variableName ) {
	this->visualize( variableName.toStdString() );
}

void Command_Agent::onAnime( const QString & variableName ) {
	LayoutInterpolation::getInstance()->setUseVP(true);
	LayoutInterpolation::getInstance()->setTimer(variableName.toFloat());
}

void Command_Agent::onUpdate() {
	this->update();
}

WOP_Entry * Command_Agent::visualize(std::string _visualItem) {

	if(_visualItem.find("script") != string::npos){//add by hyt
		scriptmode = true;
		size_t replace_target = _visualItem.find_last_of(":");
		_visualItem = _visualItem.substr(0,replace_target);
	}
	return visualize(_visualItem, NULL);
}

xMappingTree TestingDriver(int, WOP_Entry *en);

WOP_Entry * Command_Agent::visualize(std::string _visualItem, WOP_Entry *parent){ 
	
	// NOTE do we really need to clear previous type mapping?
//	MappingEngine::getInstance()->clearMDString();


	DIVA_Application::getInstance()->switchFrameListener(false);					  // disable frameStart()
	WOP_Entry *en ;
	en = retrieveWOP(_visualItem, parent, NULL, true);	

	xMappingTree* xmt  ;
	string mds = MappingEngine::getInstance()->searchMDString(en->getVarType()) ; // search existing MDS string

	if (mds == "") {
		 vmLibrary::instance().get_vm_total();
		 auto en_and_xmt = en->setupVM();
		 if( !en_and_xmt.first || !en_and_xmt.second ) {
			 // user canceled
			 return nullptr;
		 }
		 en = en_and_xmt.first;
		 xmt = en_and_xmt.second;

	} else {
		MDSParser *parser = new MDSParser();
		xmt = parser->fromMDStoXMappingTree(mds,en);
		delete parser;
	}	

	MappingEngine::getInstance()->xCreateMappedObject(xmt);
	MappingEngine::getInstance()->add_wop_xmt_pair(en, xmt);
	MappingEngine::getInstance()->addxMappingTree( xmt ); // add all the nodes to be managed by mapping engine
	DIVA_Application::getInstance()->switchFrameListener(true);					// enable frameStart()
	return en ;
}

/// fold
void Command_Agent::fold(std::string _foldItem)
{
	/// 與DIVA UI connect
}
void Command_Agent::hideOutofScopeVMs() {
	vector<WOP_Entry*> sleepwops ;
	WOP_Entry * en ;
	sleepwops = WOPM::getInstance()->queryWOPsbyInscope(false);
	std::vector<WOP_Entry*>::iterator itr;
	for (itr = sleepwops.begin();itr != sleepwops.end();itr++) {
		en = (*itr);
		//if (en->getParent() != NULL) continue ;   // if this entry has parent, it is an attribute of object or array, we will skip
		DIVA_VM *tvm = MappingEngine::getInstance()->get_vm_by_entry(en);
		//assert(tvm != NULL);
		if (tvm == NULL)continue;
		tvm->VMSetVisible(false);    
		if (tvm->getVMType()== "reference"){
			ReferenceVM* rvm = (ReferenceVM*)tvm ;
			dummyVM * dummy = (dummyVM*) rvm->getBodyVM();
			dummy->clearPointedVM();
			// dummyVM *dummy = (dummyVM *) MappingEngine::getInstance()->get_DummyVM_from_Entry(this);
		}
	}
		
}

/// update
void Command_Agent::update()
{
	CommandServer::instance().syncStart();
	CommandServer::instance().start();
	WOPM::getInstance()->updateAll();
	CommandServer::instance().end();

	/// show 出所有的wopm entry info.
	
	WOPM::getInstance()->showAll("The end of updateall() but before trigger_valueupdate()");
	hideOutofScopeVMs();
	
	/// check if the wop_entry is updated, notifies the DIVA to redraw.
	/// and set the wop entry's updated flag to false.
	/// 目前這一部分是由wopm中的update去作，但因為要與diva UI作connect，故不日會將之移出至command agent 實作
	MappingEngine::getInstance()->trigger_valueupdate(); // added by YPC 0824


	/*  20120906 先註解測試新的explor
	// if automatic exploration is set
	if (Layout_Assistant::getInstance()->getSettingAutoExplore())  {
		DIVA_VM* vm = Layout_Assistant::getInstance()->getStartingVM() ;		
		assert(vm != NULL) ;
		if (vm->get_visible() == false)  {
			  // the vm has become invisible because of out of scope
			  // so we disable automatic exploration
			Layout_Assistant::getInstance()->setStartingVM(NULL);
			Layout_Assistant::getInstance()->setSettingAutoExplore(false);
			MessageBox(_hWnd,"Auto Exploration is disabled because starting VM is out of scope","Warning",MB_OK);
		} else
			Layout_Assistant::getInstance()->expand(vm, true) ; 
	}
	*/
	// take a snap shot for animation 
	ExplorBotLibrary::getInstance()->setDo(true);
	//InterpolationCenter::getInstance()->snapShot();
	LayoutInterpolation::getInstance()->takePastSnapshot();

	//MappingEngine::getInstance()->updateArithmeticNodes();
	WOPM::getInstance()->showAll("The end of update()");
	CommandServer::instance().syncEnd();


}

bool isPriType(string type) {
	vector<string>::iterator itr = pri_types.begin();
	for (itr; itr != pri_types.end(); itr++) {
		if ((*itr) == type) return true ;
	}
	return false ;
}
void Command_Agent::reviveUnfoldedObject(WOP_Obj_Entry *shell, bool top) {
	WOP_Entry *enChild ;
	vector<WOP_Entry *> children = shell->getChildren();
    vector<WOP_Entry*>::iterator itr;

	for (itr = children.begin() ; itr != children.end(); itr++) {
		enChild = (*itr);
		string attribute = enChild->getName();
        enChild->setName(shell->getLongName()+"."+ attribute);
		enChild->setScope(true);
		enChild->setDescentFrom(shell->getDescentFrom());
		enChild->setFrom(shell->getFrom());
	}
}
void Command_Agent::unfoldObject(WOP_Obj_Entry *shell, bool top) {
	assert( shell || !"invalid object" );

	std::string className = getClassName(shell->getVarType());
	auto response = CommandServer::instance().structure( QString::fromStdString( className ) ).toMap();
	auto attrs = response["<ATTRS>"].toList();
	for( auto it = attrs.begin(); it != attrs.end(); ++it ) {
		auto attr = it->toMap();
		WOP_Entry * enChild = this->retrieveWOP( shell->getLongName() + "." + attr["<VARNAME>"].toString().toStdString(), shell, NULL, top, attr["<VARTYPE>"].toString().toStdString() );
		enChild->setDescentFrom(shell->getDescentFrom());
		enChild->setFrom(shell->getFrom());
		shell->addChild(enChild);
	}
	shell->setUnfolded(true);
    // WOPM::getInstance()->showAll("The end of unfoldObject");
}
string remove_parentheses(string buffer) {
	int last = buffer.length()-1 ;
	if (buffer.at(0) == '(' && buffer.at(last) == ')') 
		return buffer.substr(1,buffer.length()-2);
	return buffer ;
}
string de_reference(string vartype) {
	string p ;
	p = remove_parentheses(vartype);
	assert(p.at(p.length()-1) == '*');
	p = p.substr(0,p.length()-1);
	p = remove_parentheses(p);
	return p ;
}

WOP_Entry* Command_Agent::unfoldRefPure(WOP_Entry* refen){
	WOP_Entry *en = NULL;
   bool revive_sleepwop = false ;
	en = WOPM::getInstance()->check_existing_objects(refen->getVal());

	if( en && en->getScope() ) {
		return en ; // This entry has been unfolded and remained in scope
	} else if (en != NULL && en->getScope() == false) {
		revive_sleepwop = true ;  // the address is equal to a sleep wop (inscope = false)
	}
	                                                            // so we set a boolean flag 

	// the caller of unfoldRef is in the dummyVM.cpp
	// When this method is called, we are sure that there is no existing object pointed by refen
	string deref = refen->getVarType();
	deref = de_reference(deref);

	string woptype = determine_wop_type(deref);

	if (revive_sleepwop) {
		// we are going to revive an old wop but its name is no longer valid
		if (isPriType(woptype)) assert(false);
		// unfoldAnPrimitive(en);
		else if (woptype == "ref") {
			string vis = "*"+ refen->getLongName();
			WOPM::getInstance()->revive_sleepwop(en, vis, refen);
		}  else if (woptype == "array") {
			reviveArrayEntry(en, refen->getLongName(),  refen);
			reviveUnfoldedArray(dynamic_cast<WOP_Array_Entry*>(en), false);
		} else if (woptype == "object")  {
			reviveObjEntry(en, refen->getLongName(), refen);
			reviveUnfoldedObject(dynamic_cast<WOP_Obj_Entry*>(en),false);
		}
		CommandServer::instance().start();
		en->update();
		CommandServer::instance().end();

		//WOPM::getInstane()->showAll("Middle of unfoldRef()");
		return en;
	}

	// here we want to unfold a new object 
	if (isPriType(woptype)) assert(false);
		// unfoldAnPrimitive(en);
	else if (woptype == "ref") {
			string vis = "*"+ refen->getLongName();
			en = WOPM::getInstance()->createEntry(vis, woptype, NULL, refen, false, deref,refen->getVal());
			WOPM::getInstance()->addEntry(en);
	} else if (woptype == "array") {
		en = newArrayEntry(refen->getLongName(), NULL, refen, false, deref, refen->getVal());
		WOPM::getInstance()->addEntry(en);
		unfoldArray(dynamic_cast<WOP_Array_Entry*>(en), false);
	} else if (woptype == "object")  {
	    en = newObjEntry(refen->getLongName(), NULL, refen, false, deref, refen->getVal());//why the top argument is false ?
		if( !en ) {
			// address is invalid
			return nullptr;
		}
	    WOPM::getInstance()->addEntry(en);
	    unfoldObject(dynamic_cast<WOP_Obj_Entry*>(en),false); 
	}
	//WOPM::getInstance()->showAll("Middle of unfoldRef()");
	return en;
}

/// unfold a reference. This method can be called inside DIVA or at YaJDB
WOP_Entry * Command_Agent::unfoldRef(WOP_Entry *refen) {
//	DIVA_Application::getInstance()->switchFrameListener(false);				  // disable frameStart()

	WOP_Entry *en ;

	en = unfoldRefPure(refen);
	if (en==NULL) return en ;
	// WOPM::getInstance()->showAll("Middle of unfoldRef()");

	DIVA_VM *oldvm = MappingEngine::getInstance()->get_vm_by_entry(en);
	if (oldvm != NULL) {
			// the wop_entry is an old wop in WOPM. So, it has its paired VM. We do not need to apply mapping again.
			dummyVM *dummy = (dummyVM *) MappingEngine::getInstance()->get_DummyVM_from_Entry(refen);
			assert(dummy != NULL); // the dummy VM should not be NULL
			dummy->setBodyVM(oldvm);
			oldvm->VMSetVisible(true);
			xMappingTree * xmt = MappingEngine::getInstance()->get_xmt_by_entry(en);
			xmt->update();
			DIVA_Application::getInstance()->switchFrameListener(true); //20130130 add by FrankWang
			return en ;
	}

	xMappingTree* xmt  ;
	string mds = MappingEngine::getInstance()->searchMDString(en->getVarType()) ; // search existing MDS string

	if (mds == "") {
		auto en_and_xmt = en->setupVM();
		en = en_and_xmt.first;
		xmt = en_and_xmt.second;
		//xmt = mt.toXMappingTree(10,en); // the case of RGB color cube
		//MappingEngine::getInstance()->saveToMDSfile("intbt.java_intbt.mds", en->getVarType(), xmt.toMDString());
		//assert(false);
	} else {
		MDSParser parser;
		xmt = parser.fromMDStoXMappingTree(mds,en);
	}

	MappingEngine::getInstance()->xCreateMappedObject(xmt);  // create the VMs by traversing the mapping tree
	MappingEngine::getInstance()->add_wop_xmt_pair(en, xmt);
	MappingEngine::getInstance()->addxMappingTree(xmt); // add all the nodes to be managed by mapping engine
	// MappingEngine::getInstance()->createVM(mt);
//	DIVA_Application::getInstance()->switchFrameListener(true);					// enable frameStart()
	return en ;
}

void Command_Agent::unfoldRef(std::string _unfoldItem)
{
	WOP_Entry *en ;
	en = WOPM::getInstance()->searchEntrybyName(_unfoldItem, "ref");
	if (en == NULL) return ; // We should send some error message back to Minerva
	/*HERE*/

	en = unfoldRef(en);
}

WOP_Entry* Command_Agent::unfoldObjPure( WOP_Entry * objen ){
	bool revive_sleepwop = false ;
	WOP_Entry * en = WOPM::getInstance()->check_existing_objects(objen->getAddr());

	if( en && en->getScope() ) {
		return en ; // This entry has been unfolded and remained in scope
	} else if (en != NULL && en->getScope() == false) {
		revive_sleepwop = true ;  // the address is equal to a sleep wop (inscope = false)
	}
	                                                            // so we set a boolean flag 

	// the caller of unfoldRef is in the dummyVM.cpp
	// When this method is called, we are sure that there is no existing object pointed by refen

	string woptype = "object";

	if (revive_sleepwop) {
		// we are going to revive an old wop but its name is no longer valid
		reviveObjEntry(en, objen->getLongName(), nullptr);
		reviveUnfoldedObject(dynamic_cast<WOP_Obj_Entry*>(en),false);
		CommandServer::instance().start();
		en->update();
		CommandServer::instance().end();

		//WOPM::getInstane()->showAll("Middle of unfoldRef()");
		return en;
	}

	// here we want to unfold a new object
	en = newObjEntry(objen->getLongName(), NULL, nullptr, false, objen->getVarType(), objen->getAddr());//why the top argument is false ?
	if( !en ) {
		// address is invalid
		return nullptr;
	}
	WOPM::getInstance()->addEntry(en);
	unfoldObject(dynamic_cast<WOP_Obj_Entry*>(en),false);
	return en;
}

/// unfold an object.
WOP_Entry * Command_Agent::unfoldObject( WOP_Entry * objen ) {
	DIVA_Application::getInstance()->switchFrameListener(false);				  // disable frameStart()

	WOP_Entry *en ;

	en = unfoldObjPure(objen);
	if (en==NULL) return en ;

	DIVA_VM *oldvm = MappingEngine::getInstance()->get_vm_by_entry(en);
	if (oldvm != NULL) {
		// the wop_entry is an old wop in WOPM. So, it has its paired VM. We do not need to apply mapping again.
		xMappingTree * xmt = MappingEngine::getInstance()->get_xmt_by_entry(en);
		xmt->update();

		return en ;
	}

	xMappingTree* xmt  ;
	string mds = MappingEngine::getInstance()->searchMDString(en->getVarType()) ; // search existing MDS string

	if (mds == "") {
		auto en_and_xmt = en->setupVM();
		en = en_and_xmt.first;
		xmt = en_and_xmt.second;
	} else {
		MDSParser parser;
		xmt = parser.fromMDStoXMappingTree(mds,en);
	}

	MappingEngine::getInstance()->xCreateMappedObject(xmt);  // create the VMs by traversing the mapping tree
	MappingEngine::getInstance()->add_wop_xmt_pair(en, xmt);
	MappingEngine::getInstance()->addxMappingTree(xmt); // add all the nodes to be managed by mapping engine
	DIVA_Application::getInstance()->switchFrameListener(true);					// enable frameStart()
	return en ;
}

vector<int>  collectDimension(string vartype) {
	int dim ;
	string buffer = vartype ;
	bool end = false ;
	string numstr ;
	vector<int> result ;

	while (! end) {
		int index1 = buffer.find_first_of("[");
		int index2 = buffer.find_first_of("]");
		if (index1 == buffer.npos && index2 == buffer.npos ) {
			end = true ; 
			continue ;
		}
		if (index1 != buffer.npos && index2 == buffer.npos) assert(false);
		if (index1 == buffer.npos && index2 != buffer.npos) assert(false);
		assert(index2 > index1+1);
		if (index2 == index1+1) dim = 0 ; // the dimension is not known, this is the case int[][10]
		else {
			numstr = buffer.substr(index1+1, index2-index1-1) ;
			istringstream buf(numstr);
			buf >> dim  ;
			assert(dim >= 1) ;
		}
		result.push_back(dim);
		buffer = buffer.substr(index2+1);
	}

	return result ;
}
void Command_Agent::reviveArrayEntry(WOP_Entry* en, string  _visualItem, WOP_Entry* from) {
	string name ;
	if (from != NULL) name = from->getLongName();//  the object is created by an WOP (often a reference WOP) in DIVA
	else name = _visualItem ; // the object is visualized in Minerva
	en->setName(name);
	en->setFrom(from);
	en->setDescentFrom(from);
	en->setScope(true);
}
WOP_Entry* Command_Agent::newArrayEntry(string _visualItem, WOP_Entry* parent_wop, WOP_Entry* from , bool top, string vartype, string addr)
{
	// parent_wop can be a reference or pointer
	// parent_wop can be static name if parent_wop = NULL ;
	string name ;

	/// 新增出object entry
	if (from != NULL) name = from->getLongName();//  the object is created by an WOP (often a reference WOP) in DIVA
	else name = _visualItem ; // the object is visualized in Minerva

	WOP_Array_Entry* enArray = new WOP_Array_Entry(name, parent_wop);

	enArray->setFrom(from);
	enArray->setDescentFrom(from);
	enArray->setTop(top);

	enArray->setVarType(vartype);
	enArray->setAddr(addr);
	vector<int> dims = collectDimension(vartype);
	enArray->setDimensionRange(dims);

	assert(enArray != NULL);
    return enArray;
}

vector<int> computeIndexes(int eno, vector<int> dims) {
	vector<int> indexes ;
	unsigned int i = 0 ;
	int num = eno ;
	for (i=0; i< dims.size(); i++) {
		

		if (i == dims.size()-1) {  // this is the last dimension, so we do not need to divide again
			indexes.push_back(num);
			break ;
		}

		int sum = 1 ;
		// compute the total number from dimension i+1 to 0 
		for (unsigned int j=i+1; j< dims.size(); j++) 
			sum = sum * dims[j] ;

		indexes.push_back(eno/sum);
		num = num % sum;
	}
	assert(indexes.size() == dims.size());
	return indexes ;
}
	   
string genArrayIndexString(vector<int> indexes) {
	string result = "" ;
	for (unsigned int i =0 ; i< indexes.size(); i++) {
		ostringstream buf;
		buf << "[" << indexes[i] << "]" ;
		result = result + buf.str() ;
	}
	assert(result != "");
	return result ;
}
void Command_Agent::reviveUnfoldedArray(WOP_Array_Entry *shell, bool top) {
	//assert(false);  // nothing wrong here. it is just that the following code is never tested.
	                             // you should proceed with caution

	WOP_Entry *enChild ;
	vector<int> indexes ;

	vector<int> dims = shell->getDimensionRange(); // higher dimension is stored in the head of vector
	int dimno = shell->getDimension();

	// prepare the index for each dimension ;
	int maxno = 1 ;

	// compute the all the element number we need to expand
	for (int i=0; i< dimno ; i++) {
		maxno = maxno * dims[i] ;
	}
	vector<WOP_Entry *> children = shell->getChildren();
    vector<WOP_Entry*>::iterator itr;
 
	 int k= 0 ;
	for (itr = children.begin();  itr != children.end() ;  itr++ ){
		enChild = (*itr);
		indexes = computeIndexes(k,dims); // use k to divide and generate an indexes  
		string appendix = genArrayIndexString(indexes);
		string append = shell->getLongName() + appendix ;
		enChild ->setName(append);
		enChild->setDescentFrom(shell->getDescentFrom());
		enChild->setFrom(shell->getFrom());
		//shell->addChild(enChild);
		k++ ;
	} /// end for
	/// 結束，送出end給JDB
	shell->setUnfolded(true);
}


void Command_Agent::unfoldArray(WOP_Array_Entry *shell, bool top) {
	WOP_Entry *enChild ;
	vector<int> indexes ;

	std::string className = getClassName(shell->getVarType());
	//assert(cout << "get the classname :" << className << endl);

	/// 送出start的字串給JDB
	CommandServer::instance().start();
	// vector<string> att_names = send_struct_and_parse(className);
	vector<int> dims = shell->getDimensionRange(); // higher dimension is stored in the head of vector


	int dimno = shell->getDimension();

	// prepare the index for each dimension ;
	int maxno = 1 ;

	// compute the all the element number we need to expand
	for (int i=0; i< dimno ; i++) {
		maxno = maxno * dims[i] ;
	}
	for (int k=0; k < maxno ; k++) {
		indexes = computeIndexes(k,dims); // use k to divide and generate an indexes  
		string appendix = genArrayIndexString(indexes);
		string append = shell->getLongName() + appendix ;
		enChild = retrieveWOP(append, shell, NULL, top);
		enChild->setDescentFrom(shell->getDescentFrom());
		enChild->setFrom(shell->getFrom());
		shell->addChild(enChild);
		
	} /// end for

	/// 結束，送出end給JDB
	CommandServer::instance().end();
	shell->setUnfolded(true);

    // WOPM::getInstance()->showAll("The end of unfoldArray()");
}
void Command_Agent::unfoldArray(std::string _unfoldInfo)
{
	assert(false); // this function should no longer be called

}

/// stringSplit - 拆解字串，以空白為分界，回傳一個string 的vector
std::vector<std::string> Command_Agent::stringSplit(std::string str, std::string delim)
{
	int cutAt;

	std::vector<std::string> results;
	
	while( (cutAt = str.find_first_of(delim)) != str.npos )
	{
		if(cutAt > 0)
		{
			results.push_back(str.substr(0,cutAt));
		}
		str = str.substr(cutAt+1);
	}
	if(str.length() > 0)
	{
		results.push_back(str);
	}

	return results;
}

/// Given a path string, this method get the value of the variable
std::string Command_Agent::getValue(std::string s)
{
	auto response = CommandServer::instance().show( QString::fromStdString( s ) ).toMap();
	auto value = response["<VALUE>"].toString().toStdString();
	assert(!value.empty());
	return value ;
}
bool Command_Agent::check_scope(std::string s)
{
	bool ret = CommandServer::instance().scope( QString::fromStdString( s ) ).toBool();
	return ret;
}
void Tokenize(const string& str,
                      vector<string>& tokens,
                      const string& delimiters = " ")
{
    // Skip delimiters at beginning.
    string::size_type lastPos = str.find_first_not_of(delimiters, 0);
    // Find first "non-delimiter".
    string::size_type pos     = str.find_first_of(delimiters, lastPos);

    while (string::npos != pos || string::npos != lastPos)
    {
        // Found a token, add it to the vector.
        tokens.push_back(str.substr(lastPos, pos - lastPos));
        // Skip delimiters.  Note the "not_of"
        lastPos = str.find_first_not_of(delimiters, pos);
        // Find next "non-delimiter"
        pos = str.find_first_of(delimiters, lastPos);
    }
}


vector<std::string> TestingRobot(vector<std::string> attrs) {
	vector<string> returnstr ;
	if (attrs.size() == 3) {
		if (attrs[0] == "travel" && attrs[1] == "left") {
			for (unsigned int i=0; i< attrs.size(); i++) {
				returnstr.push_back(attrs[i]);
				if (i==0) returnstr.push_back("bool");
				if (i==1) returnstr.push_back("bt*");
				if (i==2) returnstr.push_back("bt*");
			}
		}
		return returnstr ;
	}
	return attrs ;
	
	
}

std::string Command_Agent::determine_wop_type(std::string vartype) {
	int index ;
	index = vartype.find_last_of("*"); 
	// if the vartype is a pointer, the last character of the string should be "*"
	if (index != vartype.npos && vartype.substr(index) == "*") 
		return "ref" ;
	
	index = vartype.find_last_of("]"); 
	// if the vartype is an array, the last character of the string should be "]"
	if (index != vartype.npos && vartype.substr(index) == "]") 
		return "array" ;

	if (vartype == "int") 		return "int" ;
	if (vartype == "bool")  		return "bool" ;
	if (vartype == "boolean")  assert(false);
	if (vartype == "char")  		return "char" ;
	if (vartype == "long")  	return "long" ;
	if (vartype == "float")  		return "float" ;
	if (vartype == "double")  		return "double" ;
 	if (vartype == "string") 		return "Stirng"  ;

    string classname, str ;
	vector<string> tokens;
    Tokenize(vartype, tokens, "[");
	str = combine_tokens(tokens);
	tokens.clear();

	Tokenize(str, tokens,"]");
	str = combine_tokens(tokens);
	tokens.clear();

	Tokenize(str,tokens,"*");

	int nameno = 0 ;
	for (unsigned int i=0;i< tokens.size(); i++) {
		if (isNumber(tokens[i]))
			assert(false) ; // the number only appear in the array index.
		                    // it should be screened as an array
		nameno++ ;
		classname = tokens[i] ;
	}
	assert(nameno == 1) ;
	return "object" ;



}
std::string combine_tokens(vector<string> tokens) {
	string result="" ;
	for (unsigned int i=0;i< tokens.size(); i++) {
		result = result + tokens[i];
	}
	return result ;
}
bool isNumber(string str) {
	for (unsigned int i = 0 ; i< str.npos ; i++) {
		if (!(str.at(i) >= '0' && str.at(i) <= '9'))
			return false ;
	}
	return true ;
}
/// getName - for WOPM
std::string Command_Agent::getClassName(std::string typestr)
{
	string str = typestr ;
	int index1 = str.find_first_of("[");
	int index2 = str.find_last_of("]");
	if (index1 != str.npos && index2 != str.npos) { // we have an array type ;
		// get rid of the array dimension part 
		string head = str.substr(0,index1);
	    string tail = str.substr(index2+1);
		str = head + tail ;
	}
		

	vector<string> tokens;
	Tokenize(str,tokens,"*");
	str = combine_tokens(tokens);
	tokens.clear();

    Tokenize(str, tokens, "(");
	str = combine_tokens(tokens);
	tokens.clear();

	Tokenize(str, tokens,")");
	assert(tokens.size() == 1) ;

	return tokens[0] ;
}

/// intToString - 將integer 轉成 string，用於處理array時的method
std::string Command_Agent::intToString(int its)
{
	std::stringstream ss;
	std::string str;

	ss << its;
	str = ss.str();
	ss.str("");

	return str;
}

/// getArrayLength
int Command_Agent::getArrayLength(std::string s)
{
	/// 預設要回傳的array長度為 0
	int arrayLength = 0;

	/// 送出詢問type的字串至yajdb
	socket_s->SendLine("[DIVACommandAgent]$", CMD_ASK + s);

	// add by ParrotT
	// 加入傳送/接收者的label
	/// 接收yajdb的回傳訊息
	std::string returnMsg = socket_s->ReceiveLine("[MinervaServer]$");

	/// 分離剖析回傳字串
	std::vector<std::string> splitMsg = stringSplit(returnMsg,NEWLINE);
	splitMsg = stringSplit(returnMsg,BLANK);
	std::vector<std::string>::iterator itr = splitMsg.begin();

	/// 接在ARRTYPE後面的就是此array的長度
	for (itr;itr != splitMsg.end();itr++)
	{
		if ((*itr).find(TYPE_ARRAY) != (*itr).npos)
		{
			arrayLength = atoi((*(itr+1)).c_str());
			return arrayLength;
		}
	}
	return arrayLength;
}

void Command_Agent::reviveObjEntry(WOP_Entry *en, string _visualItem, WOP_Entry* from) {
	assert(en != NULL);
    en->setName(_visualItem);
    en->setScope(true);
	en->setFrom(from);
	en->setDescentFrom(from);
}
/// newObjEntry
WOP_Entry* Command_Agent::newObjEntry(string _visualItem, WOP_Entry* parent_wop, WOP_Entry* from, bool top, string vartype, string addr)
{
	auto isValid = CommandServer::instance().dangling( from->getLongName().c_str() ).toInt();
	if( isValid != 1 ) {
		return nullptr;
	}

	// parent_wop can be a reference or pointer
	// parent_wop can be static name if parent_wop = NULL ;
	string name ;

	/// 新增出object entry
	

	WOP_Entry* enObj = new WOP_Obj_Entry(_visualItem, parent_wop);

	enObj->setTop(top);

	enObj->setFrom(from);
	enObj->setDescentFrom(from);
	enObj->setVarType(vartype);
	enObj->setAddr(addr);


	assert(enObj != NULL);
    return enObj;
}

/// getUnfoldLevel
int Command_Agent::getUnfoldLevel(std::string s)
{
	if (s.find("unfold1D") != s.npos)
		return 1;
	else if (s.find("unfold2D") != s.npos)
		return 2;
	else if (s.find("unfold3D") != s.npos)
		return 3;
	return 0;
}

/// makeChildName
std::string Command_Agent::makeChildName(int unfoldLevel,int currentLevel,int coorX2,int coorY2)
{
	assert(false);
	return "" ;
}

/// checkUnfold
bool Command_Agent::checkUnfold(std::string _checkName)
{
	WOP_Entry* en;

	en = WOPM::getInstance()->search(_checkName);
	if (en != NULL)
		return true;

	return false;
}

/// autoUnfold - 暫時寫來給自動unfold用的，這是為了讓2D的array能多unfold一層，故多寫的，跟unfoldRef超像，只是會回傳所有unfold出來的entry的vector
///              先用，後來可將這一部分跟unfoldRef相同的地方抓出來成function。
std::vector<WOP_Entry* > Command_Agent::autoUnfold(WOP_Entry* en){

	vector<WOP_Entry*> x ;
	assert(false);
	return x;
}

void Command_Agent::sendStepMsg(){
	if(InterpolationCenter::getInstance()->getKeyFrameNumber() == 0){
		InterpolationCenter::getInstance()->snapShot();
	}

	CommandServer::instance().step();
}
void Command_Agent::sendNextMsg(){
	if(InterpolationCenter::getInstance()->getKeyFrameNumber() == 0){
		InterpolationCenter::getInstance()->snapShot();
	}

	CommandServer::instance().next();
}
void Command_Agent::sendContMsg(){
	if(InterpolationCenter::getInstance()->getKeyFrameNumber() == 0){
		InterpolationCenter::getInstance()->snapShot();
	}

	CommandServer::instance().continue_();
}
void Command_Agent::sendOverMsg() {
	CommandServer::instance().over();
}
Command_Agent* Command_Agent::getCommand_Agent(){
	return ca;
}

// This is the test driver for creating a xMappingTree without Neige's Dialog
xMappingTree TestingDriver(int testno, WOP_Entry * en) {
	
	xMappingTree xmt ;

	switch (testno) {

	case 0: {// this is the test case for a single integer ivar in ubvm.java
			xNodeType *wp0 = new xNodeType_WOP(en);
			xMappingNode *wnode0 = xmt.create_node(wp0);

			// create vmtype mapping nodes in the second level
			xNodeType *vm0 = new xNodeType_VM(vmLibrary::instance().get_id_by_name( "CUBE_UBVM" ) );
			xMappingNode *second0 = xmt.create_node(vm0);	
			
			// connect the wop to the inport "_vm_sizex" of cube_ubvm 
			xmt.create_link(wnode0,0,second0->getInPort("_vm_name"));
			xmt.create_link(wnode0,0,second0->getInPort("_vm_sizex")); 
			xmt.create_link(wnode0,0,second0->getInPort("_vm_clickmsg")); 
			xmt.create_link(wnode0,0,second0->getInPort("_vm_yaw")); 
			}
			break ;
	
	case 1: {// this is the test case for a single integer ivar in ubvm.java
		    // second level is one VM node p
			// third level q use p's sizex and feed into rx of q
			xNodeType *wp0 = Factory_xNodeType::create_xnodetype("wop",en);
			xMappingNode *wnode0 = xmt.create_node(wp0);

			// create vmtype mapping nodes in the second level
			xNodeType *vm0 = Factory_xNodeType::create_xnodetype("CUBE_UBVM");
			xMappingNode *second0 = xmt.create_node(vm0);	

			// create vmtype mapping nodes in the THIRD level
			xNodeType *vm1 = Factory_xNodeType::create_xnodetype("CUBE_UBVM");
			xMappingNode *third0 = xmt.create_node(vm1);	

			// connect the wop to the inport "_vm_sizex" of cube_ubvm 
			xmt.create_link(wnode0,0,second0->getInPort("_vm_name"));
			xmt.create_link(wnode0,0,second0->getInPort("_vm_sizex")); 
			xmt.create_link(wnode0,0,second0->getInPort("_vm_clickmsg")); 
			//xmt.create_link(wnode0,0,second0->getInPort("_vm_yaw")); 

			xmt.create_link(second0->getOutPort("_vm_sizex"), third0->getInPort("_vm_rx"));
			}
			break ;
	case 2: {
		    // this is the test case for a single integer ivar in ubvm.java 
		    // to test the sphere_ubvm
			Factory_parameter fp(en);
			xNodeType *wp0 = Factory_xNodeType::create_xnodetype("wop",fp);
			xMappingNode *wnode0 = xmt.create_node(wp0);

			// create vmtype mapping nodes in the second level
			xNodeType *vm0 = Factory_xNodeType::create_xnodetype("CUBE_UBVM");
			xMappingNode *second0 = xmt.create_node(vm0);	

			// create vmtype mapping nodes in the THIRD level
			xNodeType *vm1 = Factory_xNodeType::create_xnodetype("SPHERE_UBVM");
			xMappingNode *third0 = xmt.create_node(vm1);	

			// connect the wop to the inport "_vm_sizex" of cube_ubvm 
			xmt.create_link(wnode0,0,second0->getInPort("_vm_name"));
			xmt.create_link(wnode0,0,second0->getInPort("_vm_sizex")); 
			xmt.create_link(wnode0,0,second0->getInPort("_vm_clickmsg")); 
			//xmt.create_link(wnode0,0,second0->getInPort("_vm_yaw")); 

			xmt.create_link(second0->getOutPort("_vm_sizex"), third0->getInPort("radius"));
			}
			break ;
	case 3: {
		    // this is the test case for a single float fvar in ubvm.java 
		    // to test the sphere_ubvm color
			Factory_parameter fp(en);
			xNodeType *wp0 = Factory_xNodeType::create_xnodetype("wop",fp);
			xMappingNode *wnode0 = xmt.create_node(wp0);

			// create vmtype mapping nodes in the THIRD level
			xNodeType *vm1 = Factory_xNodeType::create_xnodetype("SPHERE_UBVM");
			xMappingNode *second0 = xmt.create_node(vm1);	

			// connect the wop to the inport "_vm_sizex" of cube_ubvm 
			xmt.create_link(wnode0,0,second0->getInPort("_vm_r"));
			// xmt.create_link(wnode0,0,second0->getInPort("radius")); 
			//xmt.create_link(wnode0,0,second0->getInPort("_vm_yaw")); 
			}
			break ;
	case 4: {
		    // this is the test case for a pipe mapping
		    // to test the sphere_ubvm color
			Factory_parameter fp(en);
			xNodeType *wp0 = Factory_xNodeType::create_xnodetype("wop",fp);
			xMappingNode *wnode0 = xmt.create_node(wp0);

			// create a pipe mapping nodes in the second level
			Factory_parameter fp2("int*");
			xNodeType *gate = Factory_xNodeType::create_xnodetype("gate int*",fp2);
			xMappingNode *second0 = xmt.create_node(gate);

			// create a VM in the third level
			xNodeType *vm1 = Factory_xNodeType::create_xnodetype("SPHERE_UBVM");
			xMappingNode *third0 = xmt.create_node(vm1);	

			// connect the wop to the inport "_vm_sizex" of cube_ubvm 
			xmt.create_link(wnode0,0,second0->getInPort(0));
			xmt.create_link(second0,0,third0->getInPort("radius"));

			// xmt.create_link(wnode0,0,second0->getInPort("radius")); 
			//xmt.create_link(wnode0,0,second0->getInPort("_vm_yaw")); 
			}
			break ;
	case 5: {
		    // this is the test case for a pipe mapping
		    // to test the sphere_ubvm color
			Factory_parameter fp(en);
			xNodeType *wp0 = Factory_xNodeType::create_xnodetype("wop",fp);
			xMappingNode *L0 = xmt.create_node(wp0);

			// create a VM in the third level
			xNodeType *vm1 = Factory_xNodeType::create_xnodetype("CUBE_UBVM");
			xMappingNode *L1 = xmt.create_node(vm1);	

			xNodeType *vm2 = Factory_xNodeType::create_xnodetype("vmclone");
			xMappingNode *L2  = xmt.create_node(vm2);	

			// create a VM in the third level
			xNodeType *vm3 = Factory_xNodeType::create_xnodetype("SPHERE_UBVM");
			xMappingNode *L3 = xmt.create_node(vm3);	

			xmt.create_link(L0,0,L1->getInPort("_vm_sizex")); 
			xmt.create_link(L1,0,L2->getInPort(0)); // cube_ubvm connect to a vmclone
			xmt.create_link(L2->getOutPort("_vm_sizex"), L3->getInPort("radius"));
			}
			break ;
	case 6: {

			// this is the test case for a pipe mapping
		    // to test the sphere_ubvm color
			Factory_parameter fp(en);
			xNodeType *wp0 = Factory_xNodeType::create_xnodetype("wop",fp);
			xMappingNode *L0 = xmt.create_node(wp0);

			// create a VM in the first  level
			xNodeType *vm1 = Factory_xNodeType::create_xnodetype("CUBE_UBVM");
			xMappingNode *L1 = xmt.create_node(vm1);	

			// create a VM in the third level
			xNodeType *vm3 = Factory_xNodeType::create_xnodetype("SPHERE_UBVM");
			xMappingNode *L3 = xmt.create_node(vm3);	

			xmt.create_link(L0,0,L1->getInPort("_vm_sizex")); // connect wop to sizex of cube_ubvm
			                                                  // that is, the size of sizex is changed with variable
			xmt.create_link(L0,0,L1->getInPort("_vm_clickmsg"));

			xmt.create_link(L1->getOutPort("_vm_sizexscale"),L3->getInPort("_vm_sizexscale")); 
			// connect the output "scalex" to the sphere_ubvm's sizex
			} 
			break ;
	case 7: {
		    // this is the test case for to write out a xMappingTree (all the level0 mapping node is gate)
		    // to a DES file

			// first we create a composite VM, save to a file and add to Mapping node library
			xMappingTree* composite_xmt = new xMappingTree();
			Factory_parameter fp2("vm");
			xNodeType *gate = Factory_xNodeType::create_xnodetype("gate vm",fp2);
			xMappingNode *L0 = composite_xmt->create_node(gate);

			xNodeType *vm2 = Factory_xNodeType::create_xnodetype("vmclone");
			xMappingNode *L2  = composite_xmt->create_node(vm2);	

			// create a VM in the third level
			xNodeType *vm3 = Factory_xNodeType::create_xnodetype("SPHERE_UBVM");
			xMappingNode *L3 = composite_xmt->create_node(vm3);	

			composite_xmt->create_link(L0,0,L2->getInPort("vm")); // connect the gate to vmclone only has one inport
			composite_xmt->create_link(L2->getOutPort("_vm_sizex"), L3->getInPort("radius")); // connect the vmclone to a sphere_ubvm

			// The sample code to save a xmappingtree to a DES file
			string result = composite_xmt->toCompositeDEString("TEST","composite","This is a test");
			composite_xmt->saveToDESfile("test.des",result);

			// Sometimes, we do not need to save a xmappingtree to a file, we can add it to xMappingNodeTypeLibrary 
			// for immediate use.

			xMappingNodeTypeLibrary::getInstance()->add_compositevm_from_xMappingTree(
				"TEST","composite","This is a test composite VM",composite_xmt);


			// now we want to apply the new composite VM to a real case
			Factory_parameter fp(en);
			xNodeType *wp0 = Factory_xNodeType::create_xnodetype("wop",fp);
			xMappingNode *L0_wop = xmt.create_node(wp0);

			// create a VM in the third level
			xNodeType *vm_cube = Factory_xNodeType::create_xnodetype("CUBE_UBVM");
			xMappingNode *L1_cube = xmt.create_node(vm_cube);	

			xNodeType *vm_composite = Factory_xNodeType::create_xnodetype("TEST");
			xMappingNode *L2_composite = xmt.create_node(vm_composite);

			xmt.create_link(L0_wop,0,L1_cube->getInPort("_vm_sizex")); 
			xmt.create_link(L1_cube,0,L2_composite->getInPort(0)); // cube_ubvm connect to a vmclone in TEST
			}
			break ;

	case 8: {
		    // this is the test case for debugging the ticket #144 which assert false in compute_level
			// var -> gate1(int*) -> gate2(int*) -> cube_ubvm(_vm_rx);

			xNodeType *vm_cube = Factory_xNodeType::create_xnodetype("CUBE_UBVM");
			xMappingNode *L3_cube = xmt.create_node(vm_cube);

			Factory_parameter fp2("int*");
			xNodeType *gate2 = Factory_xNodeType::create_xnodetype("gate int*",fp2);
			xMappingNode *L2_gate = xmt.create_node(gate2);
			
			Factory_parameter fp1("int*");
			xNodeType *gate1 = Factory_xNodeType::create_xnodetype("gate int*",fp1);
			xMappingNode *L1_gate = xmt.create_node(gate1);
				
			Factory_parameter fp(en);
			xNodeType *wp0 = Factory_xNodeType::create_xnodetype("wop",fp);
			xMappingNode *L0_wop = xmt.create_node(wp0);

			xmt.create_link(L0_wop,0,L1_gate->getInPort("int*")); 
			xmt.create_link(L1_gate,0,L2_gate->getInPort("int*"));
			xmt.create_link(L2_gate,0,L3_cube->getInPort("_vm_rx"));
			}
			break ;
	case 9: {
		    // this is the test case for testing nested composite (momo's case
			// first we create a composite 1, save to library
			// second we create a composite 2 which use composite 2, save to library
		    // we connect the variable to composite 2
		    //  wop -> (gate(int*) (gate(int*) cube_ubvm)) -> sphere_ubvm
			
		
			xMappingTree* composite_xmt1 = new xMappingTree();

			// create the gate of the first composite
			Factory_parameter fp1("int*");
			xNodeType *c1gate = Factory_xNodeType::create_xnodetype("gate int*",fp1);
			xMappingNode *c1_L0 = composite_xmt1->create_node(c1gate);
			composite_xmt1->add_input_terminal(c1_L0); // new method that needed to be called

			// create a VM in the third level
			xNodeType *vm1 = Factory_xNodeType::create_xnodetype("CUBE_UBVM");
			xMappingNode *c1_L1 = composite_xmt1->create_node(vm1);	

			composite_xmt1->create_link(c1_L0,0,c1_L1->getInPort("_vm_sizex")); // connect the gate to vmclone only has one inport

			// The sample code to save a xmappingtree to a DES file
			string result = composite_xmt1->toCompositeDEString("composite1","composite","This is a test");
			composite_xmt1->saveToDESfile("composite1.des",result);

			// Sometimes, we do not need to save a xmappingtree to a file, we can add it to xMappingNodeTypeLibrary 
			// for immediate use.

			xMappingNodeTypeLibrary::getInstance()->add_compositevm_from_xMappingTree(
				"Composite1","composite","Inner Composite",composite_xmt1);


			// create another composite2 which use composite1
			xMappingTree* composite_xmt2 = new xMappingTree();
			Factory_parameter fp2("int*");
			xNodeType *c2gate = Factory_xNodeType::create_xnodetype("gate int*",fp2);
			xMappingNode *c2_L0 = composite_xmt2->create_node(c2gate);
			composite_xmt2->add_input_terminal(c2_L0);

			xNodeType *vm_composite = Factory_xNodeType::create_xnodetype("Composite1");
			xMappingNode *c2_L1 = composite_xmt2->create_node(vm_composite);

			composite_xmt2->create_link(c2_L0,0,c2_L1->getInPort("int*")); 
		
			xMappingNodeTypeLibrary::getInstance()->add_compositevm_from_xMappingTree(
				"Composite2","composite","Outter Composite",composite_xmt2);

			// now we want to apply the new composite VM to a real case
			Factory_parameter fp(en);
			xNodeType *wp0 = Factory_xNodeType::create_xnodetype("wop",fp);
			xMappingNode *L0_wop = xmt.create_node(wp0);
			xmt.add_input_terminal(L0_wop);

			xNodeType *vm = Factory_xNodeType::create_xnodetype("Composite2");
			xMappingNode *L1_vm = xmt.create_node(vm);
		
			xmt.create_link(L0_wop,0,L1_vm->getInPort("int*")); 

			// create a VM behind the composite 2
			xNodeType *vm3 = Factory_xNodeType::create_xnodetype("SPHERE_UBVM");
			xMappingNode *L3 = xmt.create_node(vm3);	
			xmt.create_link(L1_vm->getOutPort("_vm_sizex"),L3->getInPort("radius"));
			}
			break ;
	} // end of switch		
	return xmt ;
}

void Command_Agent::sendSVMMsg(){//this method add by hyt
	if(scriptmode){
		socket_s->SendLine("[DIVACommandAgent]$", CMD_SCRIPT_VM_DONE);
		scriptmode = false;
	}
}
int Command_Agent::getLineNumber(){
	/**新增問行號指令 , 行號只被animationCenter以及KeyFrameObject使用 , add by hyt*/

	return CommandServer::instance().line().toInt();
}

void Command_Agent::printMessage(std::string message)
{
	MessageBoxProxy* msgBox = MessageBoxProxy::getInstance();

	QString msg(message.c_str());
	msg.remove(0, 8);
	msgBox->setText(msg);
	msgBox->exec();
}
